StackBlitzでReactとJSON Serverを動かしてフロントエンドでAPIからデータを取得するサンプルをブラウザで全部動かす
フロントエンド(React)のブログを書くのに、動かせるサンプルとして StackBlitz を使っています。
StackBlitzって何?と、思った方はこちらのブログを御覧ください。 簡単に言うと、ブラウザ上でプレビューできるオンラインのコードエディタです。
フロントエンドは、基本的にデータをバックエンドAPIから取得して表示することが多いです。 そういった機能を盛り込んだブログを書くとき、StackBlitzのサンプルのデータ取得先としてバックエンドAPIをどう準備すればいいのか?というのが、悩みでした。
解決方法の一例を上げると…
- 適当なサンプルデータファイル作ってWeb APIから読み込んだ体にする?
- → TypeScriptを使いたい関係上、データ取得ライブラリによってデータ取得時の型が変わるので、それに対応するのがダルい。データ取得ライブラリ(Zodiosとか)のブログ書くのには使えない。
- Sample API的な公開サービスを利用する?
- → CORS対応ができないことが多くて利用できない。そのサービスがいつまで使えるかわからないリスクがある。
- 自前でAPIサーバを作る?
- → ブログのサンプルとしてずっとWeb APIを動かし続けるのはコストがかかるので避けたい。
といろいろ考えた結果、StackBlitz上でexpressサーバーも動くわけだし、 StackBlitz上でバックエンドAPIも動かせばいいじゃない。 という結論にいたりました。
というわけで、バックエンドサーバーとして一番簡単そうな JSON Server をStackBlitzで動かしつつ、フロントエンド(React)からAPIを叩いてデータを取得するサンプルを作ったので紹介します。
最終的には、こんなものができます。 これは画面表示用のデータをStackBlitz上で動くバックエンドから取得して、フロントエンドで表示しているサンプルです。 どちらもブラウザ上で動いています。
バックエンド(JSON Server)を作る
JSON Server は、JSONファイルを置くだけで簡単にREST APIを構築できるツールです。
本番APIで利用するというよりは、モックサーバーやテスト用のAPIサーバーとしてローカルで動かして使うことが多いです。
StackBlitz上でJSON Serverを動かすのは、超簡単です。 なぜなら、初期テンプレートとしてJSON Serverのテンプレートが用意されているからです。 画面から、ぽちぽちぽち、でJSON Serverが動きます。
New project で Backend タブを選択して、 JSON Server をぽちっとするだけで、JSON Serverの環境が構築できます。
JSON Server単独で動いているStackBlitzはこちらです。 初期テンプレートからは、ちょっとデータを変えています。
(↓ RUN PROJECT をクリックすると埋め込んだStackBlitzでコードとプレビューページが表示されます)
ブラウザ上でターミナルが動かせるので、ターミナル上で npm run backend
のコマンドを打てば、JSON Serverが起動します。
別ターミナルを開いて、 次のコマンドを叩くと、StackBlitz環境上でJSON Serverがレスポンスしていることがわかります。
$ curl http://localhost:3000/posts
フロントエンド(Vite + React + TypeScript)を作る
StackBlitz上でReactを動かすのも、超簡単です。 Reactの初期テンプレートも用意されています。
New project で Frontend タブを選択して、 React(TypeScript) をぽちっとするだけで、Reactの環境が構築できます。
このテンプレートでは、ビルドツールとして Vite が使われています。
特に変える理由もないので、そのままViteを使います。
フロントエンド(React)が単独で動いているStackBlitzはこちらです。
初期テンプレートからはちょっと表示を変えています。まだ、バックエンドからデータは取得していませんが、asyncな fetchApi
関数を定義して、取得している体でテーブル表示をしています。
npm workspace でモノレポ構成にする
ここまででバックエンドとフロントエンド、それぞれStackBlitz上で動かすことができました。
次はこの2つを、1つのStackBlitz環境で動かします。
2つのアプリケーションを1つのプロジェクトとして動かすので、 npm workspace
を使ってモノレポ構成にします。
こういうフォルダ構成です。
. ├── package.json ├── backend ... バックエンド(JSON Server) │ └── package.json └── frontend ... フロントエンド(Vite + React) └── package.json
トップフォルダの package.json
はこんな感じにして、workspaceに backend
と frontend
の2つのディレクトリを指定します。
{ "name": "react-backend-sample", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "npm run frontend", "frontend": "npm run -w frontend dev", "backend": "npm run -w backend backend" }, "workspaces": ["backend", "frontend"] }
backend
と frontend
のディレクトリには先程作った環境をそれぞれ入れて、とりあえず1つのプロジェクトにできました。
StackBlitzを開いたときは npm run dev
が実行されるので、とりあえずフロントエンドを起動するようにnpmコマンドを設定しておきます。
データ取得は、フロントエンド(React)のコードを変更して、バックエンドの db.json
からインポートするようにしてみます。
... import * as data from '../../backend/db.json'; function App(): JSX.Element { const [posts, setPosts] = useState<any[]>([]); useEffect(() => { const fetchApi = async () => { const result = data.posts; setPosts(result); }; fetchApi(); }, []); ...
ここまで作ったものが動いているStackBlitzはこちらです。
これでとりあえずフロントエンドをそれっぽく表示できました。
フロントエンドとバックエンドを同時に動かす
このままだと、フロントエンドがJSONファイルを読み込んでいるだけなので、バックエンドサーバーも動かしましょう。
もう1つターミナルを開いて、 npm run backend
を実行すれば、バックエンドサーバーも起動します。
そして、フロントエンドからバックエンドのAPIを叩いてデータを取得するように変更します。
ドキュメントの記載は見つけられなかったのですが、サンプルから察するに、以下のURLを利用するとStackBlitz上で動くプロセス間アクセスが実現できそうです。
https://<<PROJECT_NAME>>--<<PORT>>.local.webcontainer.io
環境変数 VITE_API_URL
にこのURLを設定して、フロントエンドからAPIを叩くように変更します。
VITE_API_URL=https://rednes-react-backend-sample--8080.local.webcontainer.io
... const API_URL = import.meta.env.VITE_API_URL || ''; function App(): JSX.Element { const [posts, setPosts] = useState<any[]>([]); useEffect(() => { const fetchApi = async () => { const response = await fetch(`${API_URL}/posts`); const result = await response.json(); setPosts(result); }; fetchApi(); }, []); ...
余談ですが、このプロジェクトをStackBlitz上ではなく、ローカルマシン上で動かす場合は localhost
のURLを指定すればいいです。
http://localhost:8080
なのでローカル上では .env.development.local
ファイルを作って、以下のように設定しておけば、StackBlitz上でもローカルでも動かせるようになります。
http://localhost:8080
このままだと、いちいちもう1つターミナルを立ち上げてバックエンドを起動する必要があります。 面倒です。
最後に、1つのターミナルでフロントエンドとバックエンドを同時に起動できるよう npm-run-all を導入します。
npm-run-all
は、npm scriptsを並列実行するためのツールです。
npm-run-all --parallel <task>
で指定したタスクを並列実行できます。
なので、こんな風に package.json
を npm run dev
でbackendとfrontendを並列に起動するようにすれば、StackBlitzの画面を開くと同時にフロントエンドとバックエンドが起動します。
{ "name": "react-backend-sample", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "npm-run-all --parallel backend frontend", "frontend": "npm run -w frontend dev", "backend": "npm run -w backend dev" }, "workspaces": ["backend", "frontend"], "devDependencies": { "npm-run-all": "^4.1.5" } }
フロントエンド(React)とバックエンド(JSON Server)を動かしているStackBlitzがこちらです。 最初に見せたやつです。 linter(eslint, prettier)とか細かい部分もあわせて変更しています。
おわりに
StackBlitz上でReactとJSON Serverを動かして、フロントエンドからバックエンドのAPIを叩いてデータを取得するサンプルを作りました。
StackBlitz上でバックエンドも動かせるので、フロントエンドでAPIからデータを取得するサンプルを作るときに便利です。
全部ブラウザ上で完結していて、自前でAPIサーバーを用意する必要がなくなりました。 これからこの方法をフロントエンドのブログを書くときに使っていこうと思います。